package org.budo.execute.limit.spring.mvc;

import java.lang.reflect.Method;
import java.util.concurrent.Semaphore;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.budo.execute.limit.AbstractExecuteLimitInterceptor;
import org.budo.execute.limit.exception.ExecuteLimitException;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

/**
 * @author limingwei
 * 
 * @see com.alibaba.dubbo.rpc.filter.ExecuteLimitFilter
 */
public class ExecuteLimitMvcInterceptor extends AbstractExecuteLimitInterceptor implements HandlerInterceptor {
    private static final String SEMAPHORE_KEY = "_EXECUTE_LIMIT_SEMAPHORE";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (null == handler || !(handler instanceof HandlerMethod)) {
            return true;
        }

        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        Semaphore semaphore = this.getMethodSemaphore(method);

        if (null == semaphore) {
            return true;
        }

        if (semaphore.tryAcquire()) { // 获取到信号量
            request.setAttribute(SEMAPHORE_KEY, semaphore);
            return true;
        }

        // 未获取到信号量
        throw new ExecuteLimitException(method);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        Semaphore semaphore = (Semaphore) request.getAttribute(SEMAPHORE_KEY);
        if (null != semaphore) {
            semaphore.release();
        }
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}
}